/* 
 * File:   Sphere.cpp
 * Author: brady
 * 
 * Created on February 2, 2011, 7:19 PM
 */

#include "Sphere.h"
#include "LambertianShader.h"

Sphere::Sphere() {
    Origin = Vector3D(0.0, 0.0, 0.0);
    Radius = 1.0;
    this->SetShader(new LambertianShader());
    boundingBox = new BoundingBox(Origin[0] - Radius, Origin[0]+Radius,
                       Origin[1] - Radius, Origin[1] + Radius,
                       Origin[2] - Radius, Origin[2] + Radius);

}

Sphere::Sphere(Vector3D origin, double radius)
{
    Origin = origin;
    Radius = radius;
    this->SetShader(new LambertianShader());
    boundingBox = new BoundingBox(Origin[0] - Radius, Origin[0] + Radius,
                       Origin[1] - Radius, Origin[1] + Radius,
                       Origin[2] - Radius, Origin[2] + Radius);

    type = "Sphere";
}

Sphere::~Sphere() {
}

bool Sphere::TestIntersect(Ray &ray, double tmin, double tmax, HitStruct& hitStruct)
{
    double Discriminant;
    Vector3D d = ray.GetDirection();
    Vector3D e = ray.GetOrigin();
    Vector3D& o = Origin;

    double c = (e-o).dot(e-o) - Radius*Radius;
    double b = 2 * d.dot(e-o);
    double a = d.dot(d);
    
    Discriminant = (b*b) - (4.0*a*c);
    if(Discriminant < 0)
    {
        return false;
    }

    double t0, t1, smaller, larger;
    t0 = (-b + sqrt(Discriminant)) / (2.0*a);
    t1 = (-b - sqrt(Discriminant)) / (2.0*a);
    if(t0 < t1)
    {
        smaller = t0;
        larger = t1;
    }
    else
    {
        smaller = t1;
        larger = t0;
    }

    if(smaller > tmin && smaller < tmax){
        hitStruct.tVal = smaller;
        hitStruct.shader = this->shader;
        hitStruct.normal = ray.Follow(hitStruct.tVal) - Origin;
        hitStruct.normal.normalize();
        return true;
 
    }
    if(larger > tmin && larger < tmax)
    {
      
        hitStruct.tVal = larger;
        hitStruct.shader = this->shader;
        hitStruct.normal = ray.Follow(hitStruct.tVal) - Origin;
        hitStruct.normal.normalize();
        
        return true;

    }
    return false;
}

//const Vector3D Sphere::SurfaceNormal(Ray &ray)
//{
//    Vector3D normal = Vector3D(ray.GetOrigin() - Origin);
//    normal.normalize();
//    return normal;
//}


double Sphere::GetSortValue(int sortBy)
{
    return this->Origin[sortBy];
}
